package cn.touna.jss.modules.third.geo.util;

import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.*;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Map;
import java.util.zip.GZIPInputStream;

public class HttpClientGeo {

    private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientGeo.class);

    /**
     * 从url获取结果
     *
     * @param path               URL 支持http和https
     * @param params             parname1=parvalue1&parname2=parvalue2
     * @param reqencoding        UTF-8 GBK
     * @param respencoding       UTF-8 GBK
     * @param requestMethod      POST|GET
     * @param httpConnectTimeout 连接超时时间，单位毫秒
     * @param httpReadTimeout    读取数据超时时间，单位毫秒
     * @param headerMap          http请求头部信息
     * @return
     */
    public static String getRs(String path, String params, String reqencoding,
                               String respencoding, String requestMethod, Integer httpConnectTimeout, Integer httpReadTimeout, Map<String, String> headerMap) {
        LOGGER.info("===path{}:" + path + "===params{}:" + params + "===reqencoding{}:" + reqencoding + "===respencoding{}:" + respencoding + "===requestMethod{}:" + requestMethod + "===httpConnectTimeout{}:" + httpConnectTimeout
                + "===httpReadTimeout{}:" + httpReadTimeout + "===headerMap{}:" + JSONObject.toJSON(headerMap));
        long a = System.currentTimeMillis();
        URL url = null;
        URLConnection connection = null;
        try {
            // 如有中文一定要加上，在接收方用相应字符转码即可 ,如果这里直接转换那么=和&也会一起转换
            params = trsPara(params, reqencoding);
            url = new URL(path);
            connection = url.openConnection();// 新建连接实例
            if (connection instanceof HttpsURLConnection) {
                ((HttpsURLConnection) connection).setHostnameVerifier(new HostnameVerifier() {
                    @Override
                    public boolean verify(String hostname, SSLSession session) {
                        return true;  // 不验证证书
                    }
                });
                TrustManager[] tm = {new MyX509TrustManager()};
                SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
                sslContext.init(null, tm, new java.security.SecureRandom());

                // 从上述SSLContext对象中得到SSLSocketFactory对象
                SSLSocketFactory ssf = sslContext.getSocketFactory();
                ((HttpsURLConnection) connection).setSSLSocketFactory(ssf);
                ((HttpsURLConnection) connection).setRequestMethod(requestMethod);// 提交方法POST|GET
            } else {
                ((HttpURLConnection) connection).setRequestMethod(requestMethod);// 提交方法POST|GET
            }

            if (headerMap != null)
                HttpUtils.fillHeaderMap(connection, headerMap);

            connection.setRequestProperty("Connection", "close"); //不进行持久化连接
            connection.setRequestProperty("Accept-Encoding", "gzip,deflate");

            if (httpConnectTimeout == null) {
                httpConnectTimeout = 10000;
            }
            connection.setConnectTimeout(httpConnectTimeout);// 设置连接超时时间，单位毫秒
            if (httpReadTimeout == null) {
                httpReadTimeout = 10000;
            }
            connection.setReadTimeout(httpReadTimeout);// 设置读取数据超时时间，单位毫秒
            connection.setDoInput(true);// 是否打开输出流 true|false
            connection.setDoOutput(true);// 是否打开输入流 true|false

            connection.setUseCaches(false);// 是否缓存true|false
            connection.connect();// 打开连接端口
            DataOutputStream out = new DataOutputStream(connection
                    .getOutputStream());
            out.writeBytes(params);
            out.flush();
            out.close();
            BufferedReader reader = null;
            String encode = "";
            try {

                InputStream in = null;
                if (connection.getContentEncoding() != null && !"".equals(connection.getContentEncoding()) && !"null".equals(connection.getContentEncoding())) {
                    encode = connection.getContentEncoding().toLowerCase();
                    if (encode != null && encode.indexOf("gzip") >= 0) {
                        in = new GZIPInputStream(connection.getInputStream());
                    }
                }
                if (null == in) {
                    in = connection.getInputStream();
                }

                reader = new BufferedReader(new InputStreamReader(in, respencoding));
            } catch (Exception e) {
                LOGGER.error("==========输入流异常：{}" + e);
            }
            StringBuilder buffer = new StringBuilder();
            String line = "";
            if (reader != null) {
                while ((line = reader.readLine()) != null) {
                    buffer.append(line);
                }
                reader.close();
            }
            int state = 0;
            if (connection instanceof HttpsURLConnection) {
                state = ((HttpsURLConnection) connection).getResponseCode();
            } else {
                state = ((HttpURLConnection) connection).getResponseCode();
            }
            String rs = buffer.toString().replace("&nbsp;", " ");
            LOGGER.info("==========" + path + "?" + params + "@" + headerMap + ";状态码:" + state + ";gzip:" + encode + ";返回结果:" + rs + ";耗时:" + (System.currentTimeMillis() - a));
            return rs;
        } catch (Exception e) {
            LOGGER.error("==========" + path + "?" + params, e);
            return "";
        } finally {
            if (connection != null) {
                if (connection instanceof HttpsURLConnection) {
                    ((HttpsURLConnection) connection).disconnect(); // 关闭连接
                } else {
                    ((HttpURLConnection) connection).disconnect(); // 关闭连接
                }
            }
        }
    }

    /**
     * 处理参数
     *
     * @throws UnsupportedEncodingException
     */
    public static String trsPara(String params, String reqencoding) throws UnsupportedEncodingException {
        StringBuilder sb = new StringBuilder();
        if (params == null) {
            return "";
        } else {
            String[] ps = params.split("&");
            for (int i = 0, l = ps.length; i < l; i++) {
                if (ps[i] == null) {
                    continue;
                } else {
                    String[] ps1 = ps[i].split("=");
                    if (ps1.length != 2) {
                        continue;
                    } else {
                        sb.append("&").append(ps1[0]).append("=").append(
                                URLEncoder.encode(ps1[1], reqencoding));
                    }
                }
            }
            return sb.length() <= 1 ? "" : sb.toString().substring(1);
        }
    }


    private static class MyX509TrustManager implements X509TrustManager {

        /*
         * The default X509TrustManager returned by SunX509. We’ll delegate
         * decisions to it, and fall back to the logic in this class if the default
         * X509TrustManager doesn’t trust it.
         */
        X509TrustManager sunJSSEX509TrustManager;

        MyX509TrustManager() throws Exception {
            // create a “default” JSSE X509TrustManager.

            KeyStore ks = KeyStore.getInstance("JKS");
            //ks.load(new FileInputStream("trustedCerts"), "passphrase".toCharArray());

            TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509",
                    "SunJSSE");

            tmf.init(ks);

            TrustManager tms[] = tmf.getTrustManagers();

			/*
             * Iterate over the returned trustmanagers, look for an instance of
			 * X509TrustManager. If found, use that as our “default” trust manager.
			 */
            for (int i = 0; i < tms.length; i++) {
                if (tms[i] instanceof X509TrustManager) {
                    sunJSSEX509TrustManager = (X509TrustManager) tms[i];
                    return;
                }
            }

			/*
             * Find some other way to initialize, or else we have to fail the
			 * constructor.
			 */
            throw new Exception("Couldn’t initialize");
        }

        /*
         * Delegate to the default trust manager.
         */
        public void checkClientTrusted(X509Certificate[] chain, String authType)
                throws CertificateException {
            try {
                sunJSSEX509TrustManager.checkClientTrusted(chain, authType);
            } catch (CertificateException excep) {
                // do any special handling here, or rethrow exception.
            }
        }

        /*
         * Delegate to the default trust manager.
         */
        public void checkServerTrusted(X509Certificate[] chain, String authType)
                throws CertificateException {
            try {
                sunJSSEX509TrustManager.checkServerTrusted(chain, authType);
            } catch (CertificateException excep) {
                /*
                 * Possibly pop up a dialog box asking whether to trust the cert
				 * chain.
				 */
            }
        }

        /*
         * Merely pass this through.
         */
        public X509Certificate[] getAcceptedIssuers() {
            return sunJSSEX509TrustManager.getAcceptedIssuers();
        }
    }
}
